home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / pgsql.php < prev    next >
PHP Script  |  2004-10-01  |  28KB  |  847 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Rui Hirokawa <hirokawa@php.net>                             |
  17. // |          Stig Bakken <ssb@php.net>                                   |
  18. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: pgsql.php,v 1.82 2004/09/25 21:58:00 danielc Exp $
  22.  
  23. require_once 'DB/common.php';
  24.  
  25. /**
  26.  * Database independent query interface definition for PHP's PostgreSQL
  27.  * extension.
  28.  *
  29.  * @package  DB
  30.  * @version  $Id: pgsql.php,v 1.82 2004/09/25 21:58:00 danielc Exp $
  31.  * @category Database
  32.  * @author   Rui Hirokawa <hirokawa@php.net>
  33.  * @author   Stig Bakken <ssb@php.net>
  34.  */
  35. class DB_pgsql extends DB_common
  36. {
  37.     // {{{ properties
  38.  
  39.     var $connection;
  40.     var $phptype, $dbsyntax;
  41.     var $prepare_tokens = array();
  42.     var $prepare_types = array();
  43.     var $transaction_opcount = 0;
  44.     var $dsn = array();
  45.     var $row = array();
  46.     var $num_rows = array();
  47.     var $affected = 0;
  48.     var $autocommit = true;
  49.     var $fetchmode = DB_FETCHMODE_ORDERED;
  50.  
  51.     // }}}
  52.     // {{{ constructor
  53.  
  54.     function DB_pgsql()
  55.     {
  56.         $this->DB_common();
  57.         $this->phptype = 'pgsql';
  58.         $this->dbsyntax = 'pgsql';
  59.         $this->features = array(
  60.             'prepare' => false,
  61.             'pconnect' => true,
  62.             'transactions' => true,
  63.             'limit' => 'alter'
  64.         );
  65.         $this->errorcode_map = array(
  66.         );
  67.     }
  68.  
  69.     // }}}
  70.     // {{{ connect()
  71.  
  72.     /**
  73.      * Connect to a database and log in as the specified user.
  74.      *
  75.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  76.      * @param $persistent (optional) whether the connection should
  77.      *        be persistent
  78.      *
  79.      * @return int DB_OK on success, a DB error code on failure.
  80.      */
  81.     function connect($dsninfo, $persistent = false)
  82.     {
  83.         if (!DB::assertExtension('pgsql')) {
  84.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  85.         }
  86.  
  87.         $this->dsn = $dsninfo;
  88.         $protocol = $dsninfo['protocol'] ? $dsninfo['protocol'] : 'tcp';
  89.         $connstr = '';
  90.  
  91.         if ($protocol == 'tcp') {
  92.             if ($dsninfo['hostspec']) {
  93.                 $connstr .= 'host=' . $dsninfo['hostspec'];
  94.             }
  95.             if ($dsninfo['port']) {
  96.                 $connstr .= ' port=' . $dsninfo['port'];
  97.             }
  98.         } elseif ($protocol == 'unix') {
  99.             // Allow for pg socket in non-standard locations.
  100.             if ($dsninfo['socket']) {
  101.                 $connstr .= 'host=' . $dsninfo['socket'];
  102.             }
  103.             if ($dsninfo['port']) {
  104.                 $connstr .= ' port=' . $dsninfo['port'];
  105.             }
  106.         }
  107.  
  108.         if ($dsninfo['database']) {
  109.             $connstr .= ' dbname=\'' . addslashes($dsninfo['database']) . '\'';
  110.         }
  111.         if ($dsninfo['username']) {
  112.             $connstr .= ' user=\'' . addslashes($dsninfo['username']) . '\'';
  113.         }
  114.         if ($dsninfo['password']) {
  115.             $connstr .= ' password=\'' . addslashes($dsninfo['password']) . '\'';
  116.         }
  117.         if (!empty($dsninfo['options'])) {
  118.             $connstr .= ' options=' . $dsninfo['options'];
  119.         }
  120.         if (!empty($dsninfo['tty'])) {
  121.             $connstr .= ' tty=' . $dsninfo['tty'];
  122.         }
  123.  
  124.         $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
  125.  
  126.         $ini = ini_get('track_errors');
  127.         if ($ini) {
  128.             $conn = @$connect_function($connstr);
  129.         } else {
  130.             ini_set('track_errors', 1);
  131.             $conn = @$connect_function($connstr);
  132.             ini_set('track_errors', $ini);
  133.         }
  134.         if ($conn == false) {
  135.             return $this->raiseError(DB_ERROR_CONNECT_FAILED, null,
  136.                                      null, null, strip_tags($php_errormsg));
  137.         }
  138.         $this->connection = $conn;
  139.         return DB_OK;
  140.     }
  141.  
  142.     // }}}
  143.     // {{{ disconnect()
  144.  
  145.     /**
  146.      * Log out and disconnect from the database.
  147.      *
  148.      * @return bool true on success, false if not connected.
  149.      */
  150.     function disconnect()
  151.     {
  152.         $ret = @pg_close($this->connection);
  153.         $this->connection = null;
  154.         return $ret;
  155.     }
  156.  
  157.     // }}}
  158.     // {{{ simpleQuery()
  159.  
  160.     /**
  161.      * Send a query to PostgreSQL and return the results as a
  162.      * PostgreSQL resource identifier.
  163.      *
  164.      * @param $query the SQL query
  165.      *
  166.      * @return int returns a valid PostgreSQL result for successful SELECT
  167.      * queries, DB_OK for other successful queries.  A DB error code
  168.      * is returned on failure.
  169.      */
  170.     function simpleQuery($query)
  171.     {
  172.         $ismanip = DB::isManip($query);
  173.         $this->last_query = $query;
  174.         $query = $this->modifyQuery($query);
  175.         if (!$this->autocommit && $ismanip) {
  176.             if ($this->transaction_opcount == 0) {
  177.                 $result = @pg_exec($this->connection, 'begin;');
  178.                 if (!$result) {
  179.                     return $this->pgsqlRaiseError();
  180.                 }
  181.             }
  182.             $this->transaction_opcount++;
  183.         }
  184.         $result = @pg_exec($this->connection, $query);
  185.         if (!$result) {
  186.             return $this->pgsqlRaiseError();
  187.         }
  188.         // Determine which queries that should return data, and which
  189.         // should return an error code only.
  190.         if ($ismanip) {
  191.             $this->affected = @pg_cmdtuples($result);
  192.             return DB_OK;
  193.         } elseif (preg_match('/^\s*\(?\s*(SELECT(?!\s+INTO)|EXPLAIN|SHOW)\s/si', $query)) {
  194.             /* PostgreSQL commands:
  195.                ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
  196.                CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
  197.                GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
  198.                REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
  199.                UNLISTEN, UPDATE, VACUUM
  200.             */
  201.             $this->row[(int)$result] = 0; // reset the row counter.
  202.             $numrows = $this->numrows($result);
  203.             if (is_object($numrows)) {
  204.                 return $numrows;
  205.             }
  206.             $this->num_rows[(int)$result] = $numrows;
  207.             $this->affected = 0;
  208.             return $result;
  209.         } else {
  210.             $this->affected = 0;
  211.             return DB_OK;
  212.         }
  213.     }
  214.  
  215.     // }}}
  216.     // {{{ nextResult()
  217.  
  218.     /**
  219.      * Move the internal pgsql result pointer to the next available result
  220.      *
  221.      * @param a valid fbsql result resource
  222.      *
  223.      * @access public
  224.      *
  225.      * @return true if a result is available otherwise return false
  226.      */
  227.     function nextResult($result)
  228.     {
  229.         return false;
  230.     }
  231.  
  232.     // }}}
  233.     // {{{ errorCode()
  234.  
  235.     /**
  236.      * Determine PEAR::DB error code from the database's text error message.
  237.      *
  238.      * @param  string  $errormsg  error message returned from the database
  239.      * @return integer  an error number from a DB error constant
  240.      */
  241.     function errorCode($errormsg)
  242.     {
  243.         static $error_regexps;
  244.         if (!isset($error_regexps)) {
  245.             $error_regexps = array(
  246.                 '/(([Rr]elation|[Ss]equence|[Tt]able)( [\"\'].*[\"\'])? does not exist|[Cc]lass ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
  247.                 '/[Cc]olumn [\"\'].*[\"\'] .*does not exist/' => DB_ERROR_NOSUCHFIELD,
  248.                 '/[Rr]elation [\"\'].*[\"\'] already exists|[Cc]annot insert a duplicate key into (a )?unique index.*/' => DB_ERROR_ALREADY_EXISTS,
  249.                 '/(divide|division) by zero$/'          => DB_ERROR_DIVZERO,
  250.                 '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
  251.                 '/invalid input syntax for integer/'    => DB_ERROR_INVALID_NUMBER,
  252.                 '/ttribute [\"\'].*[\"\'] not found$|[Rr]elation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
  253.                 '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,
  254.                 '/syntax error at/'                     => DB_ERROR_SYNTAX,
  255.                 '/violates not-null constraint/'        => DB_ERROR_CONSTRAINT_NOT_NULL,
  256.                 '/violates [\w ]+ constraint/'          => DB_ERROR_CONSTRAINT,
  257.                 '/referential integrity violation/'     => DB_ERROR_CONSTRAINT
  258.             );
  259.         }
  260.         foreach ($error_regexps as $regexp => $code) {
  261.             if (preg_match($regexp, $errormsg)) {
  262.                 return $code;
  263.             }
  264.         }
  265.         // Fall back to DB_ERROR if there was no mapping.
  266.         return DB_ERROR;
  267.     }
  268.  
  269.     // }}}
  270.     // {{{ fetchInto()
  271.  
  272.     /**
  273.      * Fetch a row and insert the data into an existing array.
  274.      *
  275.      * Formating of the array and the data therein are configurable.
  276.      * See DB_result::fetchInto() for more information.
  277.      *
  278.      * @param resource $result    query result identifier
  279.      * @param array    $arr       (reference) array where data from the row
  280.      *                            should be placed
  281.      * @param int      $fetchmode how the resulting array should be indexed
  282.      * @param int      $rownum    the row number to fetch
  283.      *
  284.      * @return mixed DB_OK on success, null when end of result set is
  285.      *               reached or on failure
  286.      *
  287.      * @see DB_result::fetchInto()
  288.      * @access private
  289.      */
  290.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  291.     {
  292.         $result_int = (int)$result;
  293.         $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int];
  294.         if ($rownum >= $this->num_rows[$result_int]) {
  295.             return null;
  296.         }
  297.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  298.             $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC);
  299.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  300.                 $arr = array_change_key_case($arr, CASE_LOWER);
  301.             }
  302.         } else {
  303.             $arr = @pg_fetch_row($result, $rownum);
  304.         }
  305.         if (!$arr) {
  306.             $err = pg_errormessage($this->connection);
  307.             if (!$err) {
  308.                 return null;
  309.             }
  310.             return $this->pgsqlRaiseError();
  311.         }
  312.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  313.             $this->_rtrimArrayValues($arr);
  314.         }
  315.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  316.             $this->_convertNullArrayValuesToEmpty($arr);
  317.         }
  318.         $this->row[$result_int] = ++$rownum;
  319.         return DB_OK;
  320.     }
  321.  
  322.     // }}}
  323.     // {{{ freeResult()
  324.  
  325.     /**
  326.      * Free the internal resources associated with $result.
  327.      *
  328.      * @param $result int PostgreSQL result identifier
  329.      *
  330.      * @return bool true on success, false if $result is invalid
  331.      */
  332.     function freeResult($result)
  333.     {
  334.         if (is_resource($result)) {
  335.             unset($this->row[(int)$result]);
  336.             unset($this->num_rows[(int)$result]);
  337.             $this->affected = 0;
  338.             return @pg_freeresult($result);
  339.         }
  340.         return false;
  341.     }
  342.  
  343.     // }}}
  344.     // {{{ quote()
  345.  
  346.     /**
  347.      * @deprecated  Deprecated in release 1.6.0
  348.      * @internal
  349.      */
  350.     function quote($str) {
  351.         return $this->quoteSmart($str);
  352.     }
  353.  
  354.     // }}}
  355.     // {{{ quoteSmart()
  356.  
  357.     /**
  358.      * Format input so it can be safely used in a query
  359.      *
  360.      * @param mixed $in  data to be quoted
  361.      *
  362.      * @return mixed Submitted variable's type = returned value:
  363.      *               + null = the string <samp>NULL</samp>
  364.      *               + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
  365.      *               + integer or double = the unquoted number
  366.      *               + other (including strings and numeric strings) =
  367.      *                 the data escaped according to MySQL's settings
  368.      *                 then encapsulated between single quotes
  369.      *
  370.      * @internal
  371.      */
  372.     function quoteSmart($in)
  373.     {
  374.         if (is_int($in) || is_double($in)) {
  375.             return $in;
  376.         } elseif (is_bool($in)) {
  377.             return $in ? 'TRUE' : 'FALSE';
  378.         } elseif (is_null($in)) {
  379.             return 'NULL';
  380.         } else {
  381.             return "'" . $this->escapeSimple($in) . "'";
  382.         }
  383.     }
  384.  
  385.     // }}}
  386.     // {{{ escapeSimple()
  387.  
  388.     /**
  389.      * Escape a string according to the current DBMS's standards
  390.      *
  391.      * PostgreSQL treats a backslash as an escape character, so they are
  392.      * removed.
  393.      *
  394.      * Not using pg_escape_string() yet because it requires PostgreSQL
  395.      * to be at version 7.2 or greater.
  396.      *
  397.      * @param string $str  the string to be escaped
  398.      *
  399.      * @return string  the escaped string
  400.      *
  401.      * @internal
  402.      */
  403.     function escapeSimple($str) {
  404.         return str_replace("'", "''", str_replace('\\', '\\\\', $str));
  405.     }
  406.  
  407.     // }}}
  408.     // {{{ numCols()
  409.  
  410.     /**
  411.      * Get the number of columns in a result set.
  412.      *
  413.      * @param $result resource PostgreSQL result identifier
  414.      *
  415.      * @return int the number of columns per row in $result
  416.      */
  417.     function numCols($result)
  418.     {
  419.         $cols = @pg_numfields($result);
  420.         if (!$cols) {
  421.             return $this->pgsqlRaiseError();
  422.         }
  423.         return $cols;
  424.     }
  425.  
  426.     // }}}
  427.     // {{{ numRows()
  428.  
  429.     /**
  430.      * Get the number of rows in a result set.
  431.      *
  432.      * @param $result resource PostgreSQL result identifier
  433.      *
  434.      * @return int the number of rows in $result
  435.      */
  436.     function numRows($result)
  437.     {
  438.         $rows = @pg_numrows($result);
  439.         if ($rows === null) {
  440.             return $this->pgsqlRaiseError();
  441.         }
  442.         return $rows;
  443.     }
  444.  
  445.     // }}}
  446.     // {{{ errorNative()
  447.  
  448.     /**
  449.      * Get the native error code of the last error (if any) that
  450.      * occured on the current connection.
  451.      *
  452.      * @return int native PostgreSQL error code
  453.      */
  454.     function errorNative()
  455.     {
  456.         return pg_errormessage($this->connection);
  457.     }
  458.  
  459.     // }}}
  460.     // {{{ autoCommit()
  461.  
  462.     /**
  463.      * Enable/disable automatic commits
  464.      */
  465.     function autoCommit($onoff = false)
  466.     {
  467.         // XXX if $this->transaction_opcount > 0, we should probably
  468.         // issue a warning here.
  469.         $this->autocommit = $onoff ? true : false;
  470.         return DB_OK;
  471.     }
  472.  
  473.     // }}}
  474.     // {{{ commit()
  475.  
  476.     /**
  477.      * Commit the current transaction.
  478.      */
  479.     function commit()
  480.     {
  481.         if ($this->transaction_opcount > 0) {
  482.             // (disabled) hack to shut up error messages from libpq.a
  483.             //@fclose(@fopen("php://stderr", "w"));
  484.             $result = @pg_exec($this->connection, 'end;');
  485.             $this->transaction_opcount = 0;
  486.             if (!$result) {
  487.                 return $this->pgsqlRaiseError();
  488.             }
  489.         }
  490.         return DB_OK;
  491.     }
  492.  
  493.     // }}}
  494.     // {{{ rollback()
  495.  
  496.     /**
  497.      * Roll back (undo) the current transaction.
  498.      */
  499.     function rollback()
  500.     {
  501.         if ($this->transaction_opcount > 0) {
  502.             $result = @pg_exec($this->connection, 'abort;');
  503.             $this->transaction_opcount = 0;
  504.             if (!$result) {
  505.                 return $this->pgsqlRaiseError();
  506.             }
  507.         }
  508.         return DB_OK;
  509.     }
  510.  
  511.     // }}}
  512.     // {{{ affectedRows()
  513.  
  514.     /**
  515.      * Gets the number of rows affected by the last query.
  516.      * if the last query was a select, returns 0.
  517.      *
  518.      * @return int number of rows affected by the last query or DB_ERROR
  519.      */
  520.     function affectedRows()
  521.     {
  522.         return $this->affected;
  523.     }
  524.  
  525.     // }}}
  526.     // {{{ nextId()
  527.  
  528.     /**
  529.      * Returns the next free id in a sequence
  530.      *
  531.      * @param string  $seq_name  name of the sequence
  532.      * @param boolean $ondemand  when true, the seqence is automatically
  533.      *                           created if it does not exist
  534.      *
  535.      * @return int  the next id number in the sequence.  DB_Error if problem.
  536.      *
  537.      * @internal
  538.      * @see DB_common::nextID()
  539.      * @access public
  540.      */
  541.     function nextId($seq_name, $ondemand = true)
  542.     {
  543.         $seqname = $this->getSequenceName($seq_name);
  544.         $repeat = false;
  545.         do {
  546.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  547.             $result =& $this->query("SELECT NEXTVAL('${seqname}')");
  548.             $this->popErrorHandling();
  549.             if ($ondemand && DB::isError($result) &&
  550.                 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
  551.                 $repeat = true;
  552.                 $this->pushErrorHandling(PEAR_ERROR_RETURN);
  553.                 $result = $this->createSequence($seq_name);
  554.                 $this->popErrorHandling();
  555.                 if (DB::isError($result)) {
  556.                     return $this->raiseError($result);
  557.                 }
  558.             } else {
  559.                 $repeat = false;
  560.             }
  561.         } while ($repeat);
  562.         if (DB::isError($result)) {
  563.             return $this->raiseError($result);
  564.         }
  565.         $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
  566.         $result->free();
  567.         return $arr[0];
  568.     }
  569.  
  570.     // }}}
  571.     // {{{ createSequence()
  572.  
  573.     /**
  574.      * Create the sequence
  575.      *
  576.      * @param string $seq_name the name of the sequence
  577.      * @return mixed DB_OK on success or DB error on error
  578.      * @access public
  579.      */
  580.     function createSequence($seq_name)
  581.     {
  582.         $seqname = $this->getSequenceName($seq_name);
  583.         $result = $this->query("CREATE SEQUENCE ${seqname}");
  584.         return $result;
  585.     }
  586.  
  587.     // }}}
  588.     // {{{ dropSequence()
  589.  
  590.     /**
  591.      * Drop a sequence
  592.      *
  593.      * @param string $seq_name the name of the sequence
  594.      * @return mixed DB_OK on success or DB error on error
  595.      * @access public
  596.      */
  597.     function dropSequence($seq_name)
  598.     {
  599.         $seqname = $this->getSequenceName($seq_name);
  600.         return $this->query("DROP SEQUENCE ${seqname}");
  601.     }
  602.  
  603.     // }}}
  604.     // {{{ modifyLimitQuery()
  605.  
  606.     function modifyLimitQuery($query, $from, $count, $params = array())
  607.     {
  608.         $query = $query . " LIMIT $count OFFSET $from";
  609.         return $query;
  610.     }
  611.  
  612.     // }}}
  613.     // {{{ pgsqlRaiseError()
  614.  
  615.     /**
  616.      * Gather information about an error, then use that info to create a
  617.      * DB error object and finally return that object.
  618.      *
  619.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  620.      *                          manually raising an error
  621.      * @return object  DB error object
  622.      * @see errorNative()
  623.      * @see errorCode()
  624.      * @see DB_common::raiseError()
  625.      */
  626.     function pgsqlRaiseError($errno = null)
  627.     {
  628.         $native = $this->errorNative();
  629.         if ($errno === null) {
  630.             $err = $this->errorCode($native);
  631.         } else {
  632.             $err = $errno;
  633.         }
  634.         return $this->raiseError($err, null, null, null, $native);
  635.     }
  636.  
  637.     // }}}
  638.     // {{{ _pgFieldFlags()
  639.  
  640.     /**
  641.      * Flags of a Field
  642.      *
  643.      * @param int $resource PostgreSQL result identifier
  644.      * @param int $num_field the field number
  645.      *
  646.      * @return string The flags of the field ("not_null", "default_value",
  647.      *                "primary_key", "unique_key" and "multiple_key"
  648.      *                are supported).  The default value is passed
  649.      *                through rawurlencode() in case there are spaces in it.
  650.      * @access private
  651.      */
  652.     function _pgFieldFlags($resource, $num_field, $table_name)
  653.     {
  654.         $field_name = @pg_fieldname($resource, $num_field);
  655.  
  656.         $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
  657.                                 FROM pg_attribute f, pg_class tab, pg_type typ
  658.                                 WHERE tab.relname = typ.typname
  659.                                 AND typ.typrelid = f.attrelid
  660.                                 AND f.attname = '$field_name'
  661.                                 AND tab.relname = '$table_name'");
  662.         if (@pg_numrows($result) > 0) {
  663.             $row = @pg_fetch_row($result, 0);
  664.             $flags  = ($row[0] == 't') ? 'not_null ' : '';
  665.  
  666.             if ($row[1] == 't') {
  667.                 $result = @pg_exec($this->connection, "SELECT a.adsrc
  668.                                     FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
  669.                                     WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
  670.                                     AND f.attrelid = a.adrelid AND f.attname = '$field_name'
  671.                                     AND tab.relname = '$table_name' AND f.attnum = a.adnum");
  672.                 $row = @pg_fetch_row($result, 0);
  673.                 $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
  674.                 $flags .= 'default_' . rawurlencode($num) . ' ';
  675.             }
  676.         } else {
  677.             $flags = '';
  678.         }
  679.         $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
  680.                                 FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
  681.                                 WHERE tab.relname = typ.typname
  682.                                 AND typ.typrelid = f.attrelid
  683.                                 AND f.attrelid = i.indrelid
  684.                                 AND f.attname = '$field_name'
  685.                                 AND tab.relname = '$table_name'");
  686.         $count = @pg_numrows($result);
  687.  
  688.         for ($i = 0; $i < $count ; $i++) {
  689.             $row = @pg_fetch_row($result, $i);
  690.             $keys = explode(' ', $row[2]);
  691.  
  692.             if (in_array($num_field + 1, $keys)) {
  693.                 $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
  694.                 $flags .= ($row[1] == 't') ? 'primary_key ' : '';
  695.                 if (count($keys) > 1)
  696.                     $flags .= 'multiple_key ';
  697.             }
  698.         }
  699.  
  700.         return trim($flags);
  701.     }
  702.  
  703.     // }}}
  704.     // {{{ tableInfo()
  705.  
  706.     /**
  707.      * Returns information about a table or a result set.
  708.      *
  709.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  710.      * is a table name.
  711.      *
  712.      * @param object|string  $result  DB_result object from a query or a
  713.      *                                string containing the name of a table
  714.      * @param int            $mode    a valid tableInfo mode
  715.      * @return array  an associative array with the information requested
  716.      *                or an error object if something is wrong
  717.      * @access public
  718.      * @internal
  719.      * @see DB_common::tableInfo()
  720.      */
  721.     function tableInfo($result, $mode = null)
  722.     {
  723.         if (isset($result->result)) {
  724.             /*
  725.              * Probably received a result object.
  726.              * Extract the result resource identifier.
  727.              */
  728.             $id = $result->result;
  729.             $got_string = false;
  730.         } elseif (is_string($result)) {
  731.             /*
  732.              * Probably received a table name.
  733.              * Create a result resource identifier.
  734.              */
  735.             $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
  736.             $got_string = true;
  737.         } else {
  738.             /*
  739.              * Probably received a result resource identifier.
  740.              * Copy it.
  741.              * Deprecated.  Here for compatibility only.
  742.              */
  743.             $id = $result;
  744.             $got_string = false;
  745.         }
  746.  
  747.         if (!is_resource($id)) {
  748.             return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
  749.         }
  750.  
  751.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  752.             $case_func = 'strtolower';
  753.         } else {
  754.             $case_func = 'strval';
  755.         }
  756.  
  757.         $count = @pg_numfields($id);
  758.  
  759.         // made this IF due to performance (one if is faster than $count if's)
  760.         if (!$mode) {
  761.  
  762.             for ($i=0; $i<$count; $i++) {
  763.                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
  764.                 $res[$i]['name']  = $case_func(@pg_fieldname($id, $i));
  765.                 $res[$i]['type']  = @pg_fieldtype($id, $i);
  766.                 $res[$i]['len']   = @pg_fieldsize($id, $i);
  767.                 $res[$i]['flags'] = $got_string ? $this->_pgFieldflags($id, $i, $result) : '';
  768.             }
  769.  
  770.         } else { // full
  771.             $res['num_fields']= $count;
  772.  
  773.             for ($i=0; $i<$count; $i++) {
  774.                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
  775.                 $res[$i]['name']  = $case_func(@pg_fieldname($id, $i));
  776.                 $res[$i]['type']  = @pg_fieldtype($id, $i);
  777.                 $res[$i]['len']   = @pg_fieldsize($id, $i);
  778.                 $res[$i]['flags'] = $got_string ? $this->_pgFieldFlags($id, $i, $result) : '';
  779.  
  780.                 if ($mode & DB_TABLEINFO_ORDER) {
  781.                     $res['order'][$res[$i]['name']] = $i;
  782.                 }
  783.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  784.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  785.                 }
  786.             }
  787.         }
  788.  
  789.         // free the result only if we were called on a table
  790.         if ($got_string) {
  791.             @pg_freeresult($id);
  792.         }
  793.         return $res;
  794.     }
  795.  
  796.     // }}}
  797.     // {{{ getTablesQuery()
  798.  
  799.     /**
  800.      * Returns the query needed to get some backend info
  801.      * @param string $type What kind of info you want to retrieve
  802.      * @return string The SQL query string
  803.      */
  804.     function getSpecialQuery($type)
  805.     {
  806.         switch ($type) {
  807.             case 'tables':
  808.                 return "SELECT c.relname as \"Name\"
  809.                         FROM pg_class c, pg_user u
  810.                         WHERE c.relowner = u.usesysid AND c.relkind = 'r'
  811.                         AND not exists (select 1 from pg_views where viewname = c.relname)
  812.                         AND c.relname !~ '^(pg_|sql_)'
  813.                         UNION
  814.                         SELECT c.relname as \"Name\"
  815.                         FROM pg_class c
  816.                         WHERE c.relkind = 'r'
  817.                         AND not exists (select 1 from pg_views where viewname = c.relname)
  818.                         AND not exists (select 1 from pg_user where usesysid = c.relowner)
  819.                         AND c.relname !~ '^pg_'";
  820.             case 'views':
  821.                 // Table cols: viewname | viewowner | definition
  822.                 return 'SELECT viewname FROM pg_views';
  823.             case 'users':
  824.                 // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd  |valuntil
  825.                 return 'SELECT usename FROM pg_user';
  826.             case 'databases':
  827.                 return 'SELECT datname FROM pg_database';
  828.             case 'functions':
  829.                 return 'SELECT proname FROM pg_proc';
  830.             default:
  831.                 return null;
  832.         }
  833.     }
  834.  
  835.     // }}}
  836.  
  837. }
  838.  
  839. /*
  840.  * Local variables:
  841.  * tab-width: 4
  842.  * c-basic-offset: 4
  843.  * End:
  844.  */
  845.  
  846. ?>
  847.